package com.yipao.wx.web.order;

import com.alibaba.fastjson.JSONArray;
import com.yipao.core.util.JacksonUtil;
import com.yipao.core.util.ResponseUtil;
import com.yipao.db.domain.YipaoCoupon;
import com.yipao.db.domain.goods.Goods;
import com.yipao.db.domain.goods.GoodsFormulaAttr;
import com.yipao.db.domain.order.Cart;
import com.yipao.db.domain.order.vo.CarSaveVo;
import com.yipao.db.service.CouponVerifyService;
import com.yipao.db.service.goods.GoodsService;
import com.yipao.db.service.order.CartService;
import com.yipao.wx.annotation.LoginUser;
import com.yipao.wx.service.UserInfoService;
import com.yipao.wx.service.WxCartService;
import com.yipao.wx.vo.GoodsCheckOutVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.yipao.wx.util.WxResponseCode.GOODS_UNSHELVE;

/**
 * 用户购物车服务
 *
 * @author tianhao
 */
@RestController
@RequestMapping("/wx/cart")
@Validated
@Slf4j
public class WxCartController {
    @Resource
    private CartService cartService;
    @Resource
    private UserInfoService userInfoService;
    @Resource
    private GoodsService goodsService;
    @Resource
    private CouponVerifyService couponVerifyService;
    @Resource
    private WxCartService wxCartService;


    /**
     * 用户购物车信息
     *
     * @param userId 用户ID
     * @return 用户购物车信息
     */
    @GetMapping("index")
    public Object index(@LoginUser Integer userId) {
        if (userId == null) {
            return ResponseUtil.unLogin();
        }

        List<Cart> list = cartService.queryByUidDevId(userId, userInfoService.getDevId(userId));
        List<Cart> cartList = new ArrayList<>();
        // 如果系统检查商品已删除或已下架，则系统自动删除。
        // 更好的效果应该是告知用户商品失效，允许用户点击按钮来清除失效商品。
        for (Cart cart : list) {
            cartList.add(cart);
        }

        Integer goodsCount = 0;
        BigDecimal goodsAmount = BigDecimal.valueOf(0.00);
        Integer checkedGoodsCount = 0;
        BigDecimal checkedGoodsAmount = BigDecimal.valueOf(0.00);
        for (Cart cart : cartList) {
            goodsCount += cart.getNumber();
            goodsAmount = goodsAmount.add(cart.getPrice().multiply(new BigDecimal(cart.getNumber())));
            if (cart.getChecked()) {
                checkedGoodsCount += cart.getNumber();
                checkedGoodsAmount = checkedGoodsAmount.add(cart.getPrice().multiply(new BigDecimal(cart.getNumber())));
            }
        }
        Map<String, Object> cartTotal = new HashMap<>();
        cartTotal.put("goodsCount", goodsCount);
        cartTotal.put("goodsAmount", goodsAmount);
        cartTotal.put("checkedGoodsCount", checkedGoodsCount);
        cartTotal.put("checkedGoodsAmount", checkedGoodsAmount);

        Map<String, Object> result = new HashMap<>(2);
        result.put("cartList", cartList);
        result.put("cartTotal", cartTotal);

        return ResponseUtil.ok(result);
    }

    /**
     * 加入商品到购物车
     * <p>
     * 如果已经存在购物车货品，则增加数量；
     * 否则添加新的购物车货品项。
     *
     * @param userId 用户ID
     * @param vo     购物车商品信息， { goodsId: xxx, number: xxx, formulaAttrId:{} }
     * @return 加入购物车操作结果
     */
    @PostMapping("add")
    public Object add(@LoginUser Integer userId, @RequestBody CarSaveVo vo) {
        if (userId == null) {
            return ResponseUtil.unLogin();
        }
        if (userId <= 0) {
            // 用户未绑定手机号码
            return ResponseUtil.fail(ResponseUtil.STATUS_CODE_UN_AUTH, "无操作权限,请先绑定手机号码");
        }
        if (vo == null) {
            return ResponseUtil.badArgument();
        }

        Cart cart = new Cart();
        Integer number = vo.getNumber();
        Integer goodsId = vo.getGoodsId();
        if (!ObjectUtils.allNotNull(number, goodsId, vo.getFormulaAttrIds())) {
            return ResponseUtil.badArgument();
        }
        if (number == null || number <= 0) {
            number = 1;
        }

        // 判断商品是否可以购买
        Goods goods = goodsService.findById(goodsId);
        if (goods == null || goods.getIsOnSale() == 0) {
            return ResponseUtil.fail(GOODS_UNSHELVE, "商品已下架");
        }

        BeanUtils.copyProperties(goods, cart);

        // 查询配方属性
        List<GoodsFormulaAttr> goodsFormulaAttrs = wxCartService.queryGoodsFormulaAttrList(vo.getFormulaAttrIds());
        if (goodsFormulaAttrs.isEmpty()) {
            return ResponseUtil.fail(ResponseUtil.STATUS_CODE_BAD_ARGUMENT, "请选择属性");
        }
        // 配方属性json字符串
        String goodsFormulaAttrStr = JSONArray.toJSONString(goodsFormulaAttrs);
        // 配方属性md5值
        String goodsFormulaAttrMd5 = wxCartService.getFormulaAttrMd5(goodsFormulaAttrStr);
        // 判断购物车中是否存在此规格商品
        // 商品id 用户id 设备id 属性json的token值
        Cart existCart = cartService.queryExist(goodsId, userId, userInfoService.getDevId(userId), goodsFormulaAttrMd5);
        if (existCart == null) {
            cart.setDevId(userInfoService.getDevId(userId));
            cart.setId(null);
            cart.setNumber(number.shortValue());
            cart.setGoodsName(goods.getName());
            cart.setGoodsId(goods.getId());
            // 配方属性json
            cart.setFormulaAttrJson(goodsFormulaAttrStr);
            // 配方属性md5
            cart.setFormulaAttrMd5(goodsFormulaAttrMd5);
            // 口味
            cart.setTaste(goodsFormulaAttrs.stream().map(GoodsFormulaAttr::getUnitName).collect(Collectors.joining("/")));
            cart.setPicUrl(goods.getPicUrl());
            cart.setPrice(goods.getRetailPrice());
            cart.setUserId(userId);
            cart.setChecked(true);
            cartService.add(cart);
        } else {
            // 取得规格的信息,判断规格库存
            int num = existCart.getNumber() + number;
            existCart.setNumber((short) num);
            if (cartService.updateById(existCart) == 0) {
                return ResponseUtil.updatedDataFailed();
            }
        }

        return goodsCount(userId);
    }

    /**
     * 立即购买
     * <p>
     * 和add方法的区别在于：
     * 1. 如果购物车内已经存在购物车货品，前者的逻辑是数量添加，这里的逻辑是数量覆盖
     * 2. 添加成功以后，前者的逻辑是返回当前购物车商品数量，这里的逻辑是返回对应购物车项的ID
     *
     * @param userId 用户ID
     * @param vo     购物车商品信息， { goodsId: xxx, number: xxx }
     * @return 立即购买操作结果
     */
    @PostMapping("fastAdd")
    public Object fastAdd(/*@LoginUser */Integer userId, @RequestBody CarSaveVo vo) {

        if (userId == null) {
            return ResponseUtil.unLogin();
        }
        if (vo == null) {
            return ResponseUtil.badArgument();
        }

        Cart cart = new Cart();
        Integer number = vo.getNumber();
        Integer goodsId = vo.getGoodsId();
        if (!ObjectUtils.allNotNull(number, goodsId)) {
            return ResponseUtil.badArgument();
        }
        if (number == null || number <= 0) {
            number = 1;
        }

        // 判断商品是否可以购买
        Goods goods = goodsService.findById(goodsId);
        if (goods == null || goods.getIsOnSale() == 0) {
            return ResponseUtil.fail(GOODS_UNSHELVE, "商品已下架");
        }

        // 查询配方属性
        List<GoodsFormulaAttr> goodsFormulaAttrs = wxCartService.queryGoodsFormulaAttrList(vo.getFormulaAttrIds());
        if (goodsFormulaAttrs.isEmpty()) {
            return ResponseUtil.fail(ResponseUtil.STATUS_CODE_BAD_ARGUMENT, "请选择属性");
        }
        // 配方属性字符串
        String goodsFormulaAttrStr = JSONArray.toJSONString(goodsFormulaAttrs);
        // 配方属性md5值
        String goodsFormulaAttrMd5 = wxCartService.getFormulaAttrMd5(goodsFormulaAttrStr);
        // 判断购物车中是否存在此规格商品
        Cart existCart = cartService.queryExist(goodsId, userId, userInfoService.getDevId(userId), goodsFormulaAttrMd5);
        if (existCart == null) {
            cart.setId(null);
            cart.setNumber(number.shortValue());
            cart.setGoodsId(goods.getId());
            cart.setGoodsName((goods.getName()));
            // 配方id
            cart.setFormulaId(goods.getFormulaId());
            // 配方属性字符串
            cart.setFormulaAttrJson(goodsFormulaAttrStr);
            // 配方属性md5
            cart.setFormulaAttrMd5(goodsFormulaAttrMd5);
            // 口味
            cart.setTaste(goodsFormulaAttrs.stream().map(GoodsFormulaAttr::getUnitName).collect(Collectors.joining("/")));
            cart.setGoodsSn(goods.getGoodsSn());
            cart.setPicUrl(goods.getPicUrl());
            cart.setPrice(goods.getRetailPrice());
            cart.setUserId(userId);
            cart.setChecked(true);
            cartService.add(cart);
        } else {
            // 取得规格的信息,判断规格库存(一期无需判断库存)
            int num = number;
            existCart.setNumber((short) num);
            if (cartService.updateById(existCart) == 0) {
                return ResponseUtil.updatedDataFailed();
            }
        }

        return ResponseUtil.ok(existCart != null ? existCart.getId() : cart.getId());
    }

    /**
     * 修改购物车商品货品数量
     *
     * @param userId 用户ID
     * @param cart   购物车商品信息， { id: xxx, goodsId: xxx, number: xxx }
     * @return 修改结果
     */
    @PostMapping("update")
    public Object update(@LoginUser Integer userId, @RequestBody Cart cart) {
        if (userId == null) {
            return ResponseUtil.unLogin();
        }
        Integer number = cart.getNumber().intValue();
        Integer goodsId = cart.getGoodsId();
        Integer id = cart.getId();
        if (!ObjectUtils.allNotNull(id, number, goodsId)) {
            return ResponseUtil.badArgument();
        }
        if (number == null || number <= 0) {
            number = 1;
        }

        // 判断是否存在该订单
        // 如果不存在，直接返回错误
        Cart existCart = cartService.findById(userId, id);
        if (existCart == null) {
            return ResponseUtil.badArgumentValue();
        }

        // 判断goodsId和productId是否与当前cart里的值一致
        if (!existCart.getGoodsId().equals(goodsId)) {
            return ResponseUtil.badArgumentValue();
        }

        //判断商品是否可以购买
        Goods goods = goodsService.findById(goodsId);
        if (goods == null || goods.getIsOnSale() == 0) {
            return ResponseUtil.fail(GOODS_UNSHELVE, "商品已下架");
        }

        existCart.setNumber(number.shortValue());
        if (cartService.updateById(existCart) == 0) {
            return ResponseUtil.updatedDataFailed();
        }
        return ResponseUtil.ok();
    }

    /**
     * 购物车商品货品勾选状态
     * <p>
     * 如果原来没有勾选，则设置勾选状态；如果商品已经勾选，则设置非勾选状态。
     *
     * @param userId 用户ID
     * @param body   购物车商品信息， { ids: xxx, isChecked: 1/0 }
     * @return 购物车信息
     */
    @PostMapping("checked")
    public Object checked(@LoginUser Integer userId, @RequestBody String body) {
        if (userId == null) {
            return ResponseUtil.unLogin();
        }
        if (body == null) {
            return ResponseUtil.badArgument();
        }

        List<Integer> ids = JacksonUtil.parseIntegerList(body, "ids");
        if (ids == null) {
            return ResponseUtil.badArgument();
        }

        Integer checkValue = JacksonUtil.parseInteger(body, "isChecked");
        if (checkValue == null) {
            return ResponseUtil.badArgument();
        }
        Boolean isChecked = (checkValue == 1);

        cartService.updateCheck(userId, ids, isChecked);
        return index(userId);
    }

    /**
     * 购物车商品删除
     *
     * @param userId 用户ID
     * @param body   购物车商品信息， { ids: xxx }
     * @return 购物车信息
     * 成功则
     * {
     * errno: 0,
     * errmsg: '成功',
     * data: xxx
     * }
     * 失败则 { errno: XXX, errmsg: XXX }
     */
    @PostMapping("delete")
    public Object delete(@LoginUser Integer userId, @RequestBody String body) {
        if (userId == null) {
            return ResponseUtil.unLogin();
        }
        if (body == null) {
            return ResponseUtil.badArgument();
        }

        List<Integer> ids = JacksonUtil.parseIntegerList(body, "ids");

        if (ids == null || ids.size() == 0) {
            return ResponseUtil.badArgument();
        }

        cartService.delete(ids, userId);
        return index(userId);
    }

    /**
     * 购物车商品货品数量
     * <p>
     * 如果用户没有登录，则返回空数据。
     *
     * @param userId 用户ID
     * @return 购物车商品货品数量
     */
    @GetMapping("goodscount")
    public Object goodsCount(@LoginUser Integer userId) {
        if (userId == null) {
            return ResponseUtil.ok(0);
        }

        int goodsCount = 0;
        List<Cart> cartList = cartService.queryByUid(userId);
        for (Cart cart : cartList) {
            goodsCount += cart.getNumber();
        }

        return ResponseUtil.ok(goodsCount);
    }

    /**
     * 购物车下单
     *
     * @param userId 用户ID
     * @return 购物车操作结果
     */
    @PostMapping("checkout")
    public Object checkout(@LoginUser Integer userId, GoodsCheckOutVo goodsCheckOutVo) {
        if (userId == null) {
            return ResponseUtil.unLogin();
        }

        // 团购优惠
        BigDecimal grouponPrice = BigDecimal.valueOf(0.00);
        /*YipaoGrouponRules grouponRules = grouponRulesService.findById(grouponRulesId);
        if (grouponRules != null) {
            grouponPrice = grouponRules.getDiscount();
        }*/

        Integer couponId = goodsCheckOutVo.getCouponId();
        Integer userCouponId = goodsCheckOutVo.getUserCouponId();
        Integer grouponRulesId = goodsCheckOutVo.getGrouponRulesId();

        // 商品价格
        List<Integer> cartIds = goodsCheckOutVo.getCartIds();
        List<Cart> checkedGoodsList;
        if (cartIds == null || cartIds.size() == 0) {
            checkedGoodsList = cartService.queryByUidAndChecked(userId);
        } else {
            checkedGoodsList = cartService.findByIds(userId, cartIds);
            if (checkedGoodsList == null) {
                return ResponseUtil.badArgumentValue();
            }
        }
        BigDecimal checkedGoodsPrice = BigDecimal.valueOf(0.00);
        for (Cart cart : checkedGoodsList) {
            checkedGoodsPrice = checkedGoodsPrice.add(cart.getPrice().multiply(new BigDecimal(cart.getNumber())));
        }

        // 计算优惠券可用情况
        BigDecimal tmpCouponPrice = BigDecimal.valueOf(0.00);
        Integer tmpCouponId = 0;
        Integer tmpUserCouponId = 0;
        int tmpCouponLength = 0;
       /* List<YipaoCouponUser> couponUserList = couponUserService.queryAll(userId);
        for (YipaoCouponUser couponUser : couponUserList) {
            YipaoCoupon coupon = couponVerifyService.checkCoupon(userId, couponUser.getCouponId(), couponUser.getId(), checkedGoodsPrice);
            if (coupon == null) {
                continue;
            }

            tmpCouponLength++;
            if (tmpCouponPrice.compareTo(coupon.getDiscount()) == -1) {
                tmpCouponPrice = coupon.getDiscount();
                tmpCouponId = coupon.getId();
                tmpUserCouponId = couponUser.getId();
            }
        }*/
        // 获取优惠券减免金额，优惠券可用数量
        int availableCouponLength = tmpCouponLength;
        BigDecimal couponPrice = new BigDecimal(0);
        // 这里存在三种情况
        // 1. 用户不想使用优惠券，则不处理
        // 2. 用户想自动使用优惠券，则选择合适优惠券
        // 3. 用户已选择优惠券，则测试优惠券是否合适
        if (couponId == null || couponId.equals(-1)) {
            couponId = -1;
            userCouponId = -1;
        } else if (couponId.equals(0)) {
            couponPrice = tmpCouponPrice;
            couponId = tmpCouponId;
            userCouponId = tmpUserCouponId;
        } else {
            YipaoCoupon coupon = couponVerifyService.checkCoupon(userId, couponId, userCouponId, checkedGoodsPrice);
            // 用户选择的优惠券有问题，则选择合适优惠券，否则使用用户选择的优惠券
            if (coupon == null) {
                couponPrice = tmpCouponPrice;
                couponId = tmpCouponId;
                userCouponId = tmpUserCouponId;
            } else {
                couponPrice = coupon.getDiscount();
            }
        }

        // 可以使用的其他钱，例如用户积分
        BigDecimal integralPrice = BigDecimal.valueOf(0.00);

        // 订单费用
        BigDecimal orderTotalPrice = checkedGoodsPrice.subtract(couponPrice).max(new BigDecimal(0.00));

        BigDecimal payAmount = orderTotalPrice.subtract(integralPrice);

        Map<String, Object> data = new HashMap<>(10);
        data.put("couponId", couponId);
        data.put("userCouponId", userCouponId);
        data.put("cartIds", cartIds);
        data.put("grouponRulesId", grouponRulesId);
        data.put("grouponPrice", grouponPrice);
        data.put("availableCouponLength", availableCouponLength);
        data.put("goodsTotalPrice", checkedGoodsPrice);
        data.put("couponPrice", couponPrice);
        data.put("orderTotalPrice", orderTotalPrice);
        data.put("payAmount", payAmount);
        data.put("checkedGoodsList", checkedGoodsList);
        return ResponseUtil.ok(data);
    }
}
